package org.optionparser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

public class TestingUtils {

	public static String[] RUNTIME_STRING_ARRAY_TYPE = {};
	public static String[][] RUNTIME_STRING_TWO_DIMENSIONAL_ARRAY_TYPE = {};

    public static boolean arrayIsNull(String[] array) {
        return (array == null);
    }

    public static boolean arrayIsNull(Object[] array) {
        return (array == null);
    }

	public static boolean arrayIsNotNull(String[] array) {
		return (array != null);
	}

	public static String[] insertArrayIntoArray(String[] sourceArray,
			String[] insertedArray, int position) {

		// check input arrays
		if (arrayIsNull(sourceArray)) {
			return insertedArray;
		}
		if (arrayIsNull(insertedArray)) {
			return sourceArray;
		}

		// create vector that contains source array
		Vector<String> result = new Vector<String>();
		for (String sourceRecord : sourceArray) {
			result.add(sourceRecord);
		}

		// insert inserted array
		int insertPosition = position;
		insertPosition = Math.min(Math.max(0, position), sourceArray.length);
		for (int indexOfInsertedString = insertedArray.length - 1; indexOfInsertedString >= 0; indexOfInsertedString--) {
			result.insertElementAt(insertedArray[indexOfInsertedString],
					insertPosition);
		}

		return result.toArray(RUNTIME_STRING_ARRAY_TYPE);
	}

	public static String OPTIONS_VALUE_SEPARATOR = "=";

	/**
	 * 
	 * @param optionName
	 *            option name
	 * @param optionValues
	 *            option possible values
	 * @param joinOptionAndValue
	 *            if true, generated combination will contain also option and
	 *            value as one argument
	 * @param otherArgumentsAndOptions
	 *            it is recommended to have at least two
	 *            arguments/options,option will be inserted into the beginning,
	 *            middle and end of this array
	 * @return generated combinations
	 */
	public static String[][] createAllCombinationsWithValue(String optionName,
			String[] optionValues, boolean includeJoinedOptionAndValue,
			String[] otherArgumentsAndOptions) {

		List<String[]> result = new LinkedList<String[]>();

		for (String optionValue : optionValues) {
			// prepare combinations of option and it's value
			String optionJoinedWithValue = optionName + OPTIONS_VALUE_SEPARATOR
					+ optionValue;
			String[] joinedOptionAndValueArray = { optionJoinedWithValue };
			String[] separatedOptionAndValueArray = { optionName, optionValue };

			// create array, that contains only current option with value
			if (includeJoinedOptionAndValue) {
				result.add(joinedOptionAndValueArray);
			}
			result.add(separatedOptionAndValueArray);

			// ---------------------------------------
			// mix option and value with other options

			// create array with joined option and value
			if (includeJoinedOptionAndValue) {

				result.add(insertArrayIntoArray(otherArgumentsAndOptions,
						joinedOptionAndValueArray, 0));

				if (arrayIsNotNull(otherArgumentsAndOptions)) {
					result.add(insertArrayIntoArray(otherArgumentsAndOptions,
							joinedOptionAndValueArray,
							otherArgumentsAndOptions.length / 2));
					result.add(insertArrayIntoArray(otherArgumentsAndOptions,
							joinedOptionAndValueArray,
							otherArgumentsAndOptions.length));
				}
			}

			// create arrays with separated option and value
			result.add(insertArrayIntoArray(otherArgumentsAndOptions,
					separatedOptionAndValueArray, 0));
			if (arrayIsNotNull(otherArgumentsAndOptions)) {
				result.add(insertArrayIntoArray(otherArgumentsAndOptions,
						separatedOptionAndValueArray,
						otherArgumentsAndOptions.length / 2));
				result.add(insertArrayIntoArray(otherArgumentsAndOptions,
						separatedOptionAndValueArray,
						otherArgumentsAndOptions.length));
			}

		}

		return result.toArray(RUNTIME_STRING_TWO_DIMENSIONAL_ARRAY_TYPE);
	}

	/**
	 * @param optionName
	 *            name of tested option
	 * @param otherArgumentsAndOptions
	 *            option will be inserted into the begining, middle and end of
	 *            this array
	 * @return generated combinations
	 */
	public static String[][] createAllCombinationsWithoutValue(
			String optionName, String[] otherArgumentsAndOptions) {
		ArrayList<String[]> result = new ArrayList<String[]>();

		String[] optionArray = { optionName };

		result.add(optionArray);
		if (arrayIsNotNull(otherArgumentsAndOptions)) {
			result.add(insertArrayIntoArray(otherArgumentsAndOptions,
					optionArray, 0));
			result.add(insertArrayIntoArray(otherArgumentsAndOptions,
					optionArray, otherArgumentsAndOptions.length / 2));
			result.add(insertArrayIntoArray(otherArgumentsAndOptions,
					optionArray, otherArgumentsAndOptions.length));
		}

		return result.toArray(RUNTIME_STRING_TWO_DIMENSIONAL_ARRAY_TYPE);

	}
	

	

	/**
	 * Concatenate all arrays into one array of string array
	 * 
	 * @param arraysToConcatenate
	 *            arrays of string arrays
	 * @return
	 */
	public static String[][] concatenateStringArrays(
			String[][]... arraysToConcatenate) {
		List<String[]> result = new LinkedList<String[]>();
		for (String[][] arrayOfStringArray : arraysToConcatenate) {
			for (String[] stringArray : arrayOfStringArray) {
				result.add(stringArray);
			}
		}
		return result.toArray(RUNTIME_STRING_TWO_DIMENSIONAL_ARRAY_TYPE);

	}


}
